import * as vscode from 'vscode';
import * as utils from "../utils";
import * as path from "path";

const todoStore:any = {}

type TypeTodoItemInfo = {
    name: string;
    desc: string;
    path: string;
    line?: number;
    items?: TypeTodoItemData;
};
type TypeTodoItemData = TypeTodoItemInfo[];
// 树节点
export class TodoItem extends vscode.TreeItem {
    private items: TypeTodoItemData = [];
    private isDescItemStatus: boolean = false;
    private fileName: string = "";
    private todoLine: number = 0;
    setFileName(file: string): void {
        this.fileName = file;
    }
    getFileName(): string {
        return this.fileName;
    }
    setItems(newItems: TypeTodoItemData): void {
        this.items = newItems;
    }
    getItems():TypeTodoItemData {
        return this.items;
    }
    setDescItem(isDescItem: boolean): void {
        this.isDescItemStatus = isDescItem;
    }
    isDescItem(): boolean {
        return this.isDescItemStatus;
    }
    getLine(): number {
        return this.todoLine;
    }
    setLine(lineNumber: number): void {
        this.todoLine = lineNumber;
    }
}

//树的内容组织管理
export class EntryList implements vscode.TreeDataProvider<TodoItem>
{
    private _onDidChangeTreeData: vscode.EventEmitter<TodoItem | undefined | null | void> = new vscode.EventEmitter<TodoItem | undefined | null | void>();
    readonly onDidChangeTreeData: vscode.Event<TodoItem | undefined | null | void> = this._onDidChangeTreeData.event;
    // onDidChangeTreeData?: vscode.Event<void | TodoItem | null | undefined> | undefined;
    getTreeItem(element: TodoItem): vscode.TreeItem | Thenable<vscode.TreeItem> {
        return element;
    }
    getChildren(element?: TodoItem): vscode.ProviderResult<TodoItem[]> {
        if (element) {//子节点
            const childs:TodoItem[]  = [];
            const todoItemsData = element.getItems() || [];
            const isDescItem = element.isDescItem();
            for(const item of todoItemsData) {
                if(!isDescItem) {
                    const titleItem = new TodoItem(item.name, vscode.TreeItemCollapsibleState.Collapsed);
                    titleItem.setDescItem(true);
                    titleItem.setFileName(item.path);
                    titleItem.iconPath = path.resolve(__dirname, "../img/file.svg");
                    if(item.items) {
                        titleItem.setItems(item.items);
                    }
                    childs.push(titleItem);
                } else {
                    // todo value
                    const descItem = new TodoItem(item.desc, vscode.TreeItemCollapsibleState.None);
                    descItem.description = `(line: ${item.line})`;
                    descItem.setFileName(element.getFileName());
                    descItem.iconPath = path.resolve(__dirname, "../img/icon_todo.png");
                    descItem.contextValue = "todoItem";
                    (item.line as number)> 0 && descItem.setLine(item.line as number);
                    childs.push(descItem);
                }
            }
            return childs;
        } else { //根节点
            const rootList:TodoItem[] = [];
            Object.keys(todoStore).map((appKey, index) => {
                const newItem = new TodoItem(appKey, index === 0 ? vscode.TreeItemCollapsibleState.Expanded : vscode.TreeItemCollapsibleState.Collapsed);
                const newItemData = todoStore[appKey].items || {}; // sourceData
                const newTodoItemData: TypeTodoItemData = [];
                const appPath = todoStore[appKey].path;
                newItem.description = appPath;
                newItem.iconPath = path.resolve(__dirname, "../img/icon_app.png");
                Object.keys(newItemData).map((itemLocation: string) => {
                    newTodoItemData.push({
                        name: utils.getResolveFileName(itemLocation, appPath),
                        desc: "",
                        path: itemLocation,
                        items: newItemData[itemLocation]
                    });
                });
                if(newTodoItemData.length < 1) {
                    newItem.collapsibleState = vscode.TreeItemCollapsibleState.None;
                }
                newItem.setItems(newTodoItemData);
                rootList.push(newItem)
            });
            return rootList;
        }
    }
    refresh(update?: boolean): void {
        const folders = vscode.workspace.workspaceFolders;
        folders?.map((appFolder) => {
            const data:any = {
                path: appFolder.uri.path,
                name: appFolder.name,
                items: {}
            };
            const appRootPath = appFolder.uri.path;
            let hasTodoItem = false;
            utils.scanFiles(appFolder.uri.path, (opt) => {
                if(/\.(js|ts|tsx|vue|less|scss|css)/i.test(opt.fileName)) {
                    const txt = utils.readFile(opt.fileName);
                    let txtArr = txt.split(/\r\n/);
                    txtArr = txtArr.length === 1 ? txtArr[0].split("\n") : txtArr;
                    txtArr.map((lineText: string, lineIndex) => {
                        const lineMatch = lineText.match(/(\/\/|\*|\/\*)\s*todo\:([\s\S]*)/i);
                        if(lineMatch) {
                            const todoDesc = lineMatch[2].replace(/^\s*/, "").replace(/\s*$/, "");
                            if(!data.items[opt.fileName]) {
                                data.items[opt.fileName] = [];
                            }
                            data.items[opt.fileName].push({
                                desc: todoDesc,
                                name: utils.getResolveFileName(opt.fileName, appRootPath),
                                line: lineIndex + 1
                            });
                            hasTodoItem = true;
                        }
                    });
                }
            }, {
                ignore: [/\/node_modules(\/|$)/, /\/\.vscode(\/|$)/, /\/\.git(\/|$)/],
                config: utils.getExtensionConfig(),
                rootPath: utils.getRootPath()
            });
            if(hasTodoItem) {
                todoStore[appFolder.name] = data;
            }
        });
        update && this._onDidChangeTreeData.fire();
    }
    update(): void {
        this._onDidChangeTreeData.fire();
    }
}

export const activeContext = (context:vscode.ExtensionContext) => {
    //注册侧边栏面板的实现
    const todoTree = new EntryList();
    todoTree.refresh();
	vscode.window.registerTreeDataProvider("todo_tree", todoTree);
    let disposableRefresh = vscode.commands.registerCommand("eui.todoTree.refresh", () => {
        todoTree.refresh(true);
        let todoCount = 0;
        Object.keys(todoStore).map((appKey) => {
            const appData = todoStore[appKey];
            if(appData.items) {
                Object.keys(appData.items).map((fileName) => {
                    todoCount += appData.items[fileName].length;
                });
            }
        });
        vscode.window.showInformationMessage(`${todoCount} todo items found.`);
    });
    let disposableHelp = vscode.commands.registerCommand("eui.todoTree.help", () => {
        vscode.window.showInformationMessage(`Add a comment that starts with the todo keyword to the script file.`);
    });
    let disposableView = vscode.commands.registerCommand("eui.todoTree.view", (argv:any) => {
        const lineNumber = argv.todoLine;
        const fileName = argv.fileName;
        if(utils.fileExists(fileName)) {
            vscode.workspace.openTextDocument(fileName).then((doc) => {
                if(lineNumber >= 0 && lineNumber < doc.lineCount) {
                    doc.lineAt(lineNumber);
                } else if(lineNumber >= doc.lineCount) {
                    doc.lineAt(lineNumber - 1);
                }
                vscode.window.showTextDocument(doc);
            }, (err) => {
                console.error(err);
            });
        }
    });
    vscode.languages.registerCompletionItemProvider([
        { scheme: "file", language: "javascript" },
        { scheme: "file", language: "javascriptreact" },
        { scheme: "file", language: "typescript" },
        { scheme: "file", language: "typescriptreact" },
        { scheme: "file", language: "css" },
        { scheme: "file", language: "less" },
        { scheme: "file", language: "scss" },
        { scheme: "file", language: "php" },
        { scheme: "file", language: "html" }
    ], {
        provideCompletionItems: (document, position) => {
            const lineData = document.lineAt(position.line - 1);
            const lineText = lineData?.text;
            const lineMatch = lineText.match(/(\/\/|\*|\/\*)\s*todo\:([\s\S]*)/i);
            if(lineMatch) {
                const todoDesc = lineMatch[2].replace(/^\s*/, "").replace(/\s*$/, "");
                const fileName = document.fileName;
                const folders = vscode.workspace.workspaceFolders || [];
                for(const folder of folders) {
                    if(fileName.substr(0, folder.uri.path.length) === folder.uri.path) {
                        if(todoStore[folder.name]) {
                            const items = todoStore[folder.name].items;
                            if(items[fileName]) {
                                const allList = todoStore[folder.name].items[fileName] || [];
                                let hasUpdate = false;
                                for(let i=0;i<allList.length;i++) {
                                    const item = allList[i];
                                    if(item.line === position.line) {
                                        todoStore[folder.name].items[fileName][i] = {
                                            desc: todoDesc,
                                            name: utils.getResolveFileName(fileName, folder.uri.path),
                                            line: position.line
                                        };
                                        hasUpdate = true;
                                        break;
                                    }
                                }
                                !hasUpdate && todoStore[folder.name].items[fileName].push({
                                    desc: todoDesc,
                                    name: utils.getResolveFileName(fileName, folder.uri.path),
                                    line: position.line
                                });
                            } else {
                                todoStore[folder.name].items[fileName] = [{
                                    desc: todoDesc,
                                    name: utils.getResolveFileName(fileName, folder.uri.path),
                                    line: position.line
                                }];
                            }
                        } else {
                            todoStore[folder.name] = {
                                path: folder.uri.path,
                                name: folder.name,
                                items: {}
                            };
                            todoStore[folder.name].items[fileName] = [{
                                desc: todoDesc,
                                name: utils.getResolveFileName(fileName, folder.uri.path),
                                line: position.line
                            }];
                        }
                        todoTree.update();
                        break;
                        // find rootPath
                    }
                }
            }
            return [];
        }
    }, "\n","\r");
    context.subscriptions.push(disposableView);
    context.subscriptions.push(disposableRefresh);
    context.subscriptions.push(disposableHelp);
};
